package is.api.demo.isgateway.utils;

import is.api.demo.isgateway.support.IsGateWayHttpResponseBody;
import is.api.demo.isgateway.support.RequestHeader;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Objects;

/**
 * httpclient连接池
 *
 * @author chen.chen
 */
@SuppressWarnings("all")
public abstract class IsGateWayHttpClientUtils {
    private final static String HTTPS_SCHEMA = "https";
    private final static String HTTP_SCHEMA = "http";
    //http客户端
    private static volatile CloseableHttpClient httpClient = null;
    //https客户端
    private static volatile CloseableHttpClient httpsClient = null;

    static {
        httpClient = httpClientBuild();
        try {
            httpsClient = httpsClientBuild();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
    }

    /**
     * httpClient客户端
     *
     * @return
     */
    private static CloseableHttpClient httpClientBuild() {
        final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        // 总连接池数量
        connectionManager.setMaxTotal(100);
        // 可为每个域名设置单独的连接池数量
        // setConnectTimeout：设置建立连接的超时时间
        // setConnectionRequestTimeout：从连接池中拿连接的等待超时时间
        // setSocketTimeout：发出请求后等待对端应答的超时时间
        final RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)
                .setConnectionRequestTimeout(5000)
                .setSocketTimeout(5000)
                .build();
        // 重试处理器，StandardHttpRequestRetryHandler
        final HttpRequestRetryHandler retryHandler = new StandardHttpRequestRetryHandler();
        return HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .setRetryHandler(retryHandler)
                .build();
    }

    /**
     * httpsClient客户端
     *
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    private static CloseableHttpClient httpsClientBuild() throws NoSuchAlgorithmException, KeyManagementException {
        // 1. 创建信任所有证书的SSLContext
        final TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {
                    }

                    public void checkServerTrusted(X509Certificate[] chain, String authType) {
                    }

                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                }
        };
        final SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

        // 2. 配置连接池和超时
        final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(100);
        final RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)
                .setConnectionRequestTimeout(5000)
                .setSocketTimeout(5000)
                .build();

        // 3. 构建HttpClient（整合SSL忽略配置）
        return HttpClients.custom()
                //.setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)) // 关键修改
                .setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE)) // 关键修改
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .setRetryHandler(new StandardHttpRequestRetryHandler())
                .build();
    }

    /**
     * 发送请求
     *
     * @param uri         请求地址
     * @param requestBody 请求体
     * @param headers     请求头
     * @return
     * @throws IOException
     */
    public static IsGateWayHttpResponseBody doHttpPost(final String uri,
                                                       final String requestBody,
                                                       final Map<String, String> headers) throws IOException {
        Assert.hasText(uri, "uri不能为空");
        try {
            final HttpPost httpPost = new HttpPost(uri);
            CloseableHttpResponse response = null;
            try {
                IsGateWayHttpResponseBody isGateWayHttpResponseBody = null;
                //添加请求头
                if (!headers.isEmpty()) {
                    headers.forEach((headerName, value) -> httpPost.addHeader(headerName, value));
                }
                //添加请求内容
                if (IsGateWayStringUtils.hasText(requestBody)) {
                    final StringEntity body = new StringEntity((String) requestBody, StandardCharsets.UTF_8);
                    httpPost.setEntity(body);
                }
                //设置请求类型
                httpPost.addHeader(RequestHeader.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString());
                //执行请求
                response = doExecute(httpPost);
                final Header[] allHeaders = response.getAllHeaders();

                //获取状态码并判断
                final int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == HttpStatus.SC_OK) {
                    // 通信成功，可以安全地读取响应内容
                    System.out.println("请求成功！状态码：" + statusCode);
                } else {
                    // HTTP 请求本身成功，但服务器返回了错误状态码（如404, 500等）
                    System.err.println("请求未成功。状态码：" + statusCode);
                }
                // 返回响应内容
                final HttpEntity entity = response.getEntity();

                if (null != entity) {
                    final String responseBody = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                    isGateWayHttpResponseBody = new IsGateWayHttpResponseBody(allHeaders, statusCode, entity, responseBody);
                    return isGateWayHttpResponseBody;
                } else {
                    isGateWayHttpResponseBody = new IsGateWayHttpResponseBody(allHeaders, statusCode, entity, null);
                    return isGateWayHttpResponseBody;
                }
            } catch (IOException e) {
                // 处理异常：处理网络不通、超时等导致的通信失败
                System.err.println("网络通信出现异常：" + e.getMessage());
                //异常处理，此处暂略
                e.printStackTrace();
                throw e;
            } finally {
                if (response != null) {
                    HttpClientUtils.closeQuietly(response);
                }
                httpPost.releaseConnection();
            }
        } catch (IOException e) {
            // 处理异常：创建HttpPost失败
            System.err.println("创建HttpPost失败：" + e.getMessage());
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * 寻找不同的客户端发送请求
     *
     * @param httpPost
     * @return
     * @throws IOException
     * @throws ClientProtocolException
     */
    private static CloseableHttpResponse doExecute(
            final HttpPost httpPost) throws IOException, ClientProtocolException {
        final URI uri = httpPost.getURI();
        if (Objects.isNull(uri)) {
            return null;
        }
        if (!StringUtils.hasText(uri.getScheme())) {
            return null;
        }
        if (uri.getScheme().equalsIgnoreCase(HTTPS_SCHEMA)) {
            CloseableHttpResponse response = httpsClient.execute(httpPost);
            return response;
        }
        if (uri.getScheme().equalsIgnoreCase(HTTP_SCHEMA)) {
            CloseableHttpResponse response = httpClient.execute(httpPost);
            return response;
        }
        throw new IllegalArgumentException("参数异常,uri=" + uri);
    }
}